from pymodbus.client import ModbusSerialClient as ModbusClient                # pymodbus >= 3.0.0
# from pymodbus.client.sync import ModbusSerialClient as ModbusClient              # pymodbus < 3.0.0
import time


class SimoModbus:
    def __init__(self, port):
        """初始化 Modbus 客户端"""
        self.client = ModbusClient(
            method='rtu',
            port=port,
            baudrate=9600,
            stopbits=2,
            bytesize=8,
            parity='N',
            timeout=5
        )
        if not self.client.connect():
            raise Exception("无法连接到 Modbus 设备")

    def read_status(self):
        """读取当前状态（D0 寄存器）"""
        try:
            response = self.client.read_holding_registers(address=0x1000, count=1, slave=1)
            if response.isError():
                print(f"读取状态失败，原始响应: {response}")
                raise Exception("读取状态失败")
            status = response.registers[0]
            return status
        except Exception as e:
            print(f"读取状态时发生错误: {e}")
            raise

    def write_coil(self, address, value):
        """写入线圈寄存器（适用于 M 类寄存器）"""
        try:
            response = self.client.write_coil(address=address, value=value, slave=1)
            if response.isError():
                print(f"写入地址 {hex(address)} 失败，原始响应: {response}")
                raise Exception(f"写入地址 {hex(address)} 失败")
            print(f"成功写入地址 {hex(address)}，值: {value}")
        except Exception as e:
            print(f"写入地址 {hex(address)} 时发生错误: {e}")
            raise

    def start_tear(self):
        """开始撕膜"""
        print("开始撕膜...")
        try:
            # 写入 0xFF00 启动撕膜操作
            self.write_coil(0x0814, True)  # True 转换为 0xFF00
            time.sleep(1)  # 等待设备执行动作

            # 检查状态是否变为撕膜完成
            while True:
                status = self.read_status()
                if status == 2:  # STATUS_TEAR_COMPLETE
                    print("撕膜已完成")
                    break
                elif status == 3:  # STATUS_TEARING
                    print("正在撕膜中，请稍候...")
                    time.sleep(1)
                else:
                    print(f"未知状态: {status}")
                    break

            # 撕膜完成后执行复位操作
            print("撕膜完成，开始复位...")
            self.manual_reset()

        finally:
            # 动作完成后，重置撕膜寄存器为 0x0000
            print("重置撕膜寄存器...")
            self.write_coil(0x0814, False)  # False 转换为 0x0000

    def manual_reset(self):
        """手动复位"""
        print("执行手动复位...")
        try:
            # 写入 0xFF00 启动复位操作
            self.write_coil(0x083C, True)
            time.sleep(1)  # 等待设备执行动作

            # 检查状态是否变为准备撕膜
            while True:
                status = self.read_status()
                if status == 0:  # STATUS_READY
                    print("复位完成")
                    break
                elif status == 1:  # STATUS_RESETTING
                    print("正在复位中，请稍候...")
                    time.sleep(1)
                else:
                    print(f"未知状态: {status}")
                    break

        finally:
            # 动作完成后，重置复位寄存器为 0x0000
            print("重置复位寄存器...")
            self.write_coil(0x083C, False)

    def clear_count(self):
        """清除计数"""
        print("清除计数...")
        try:
            # 写入 0xFF00 清除计数
            self.write_coil(0x081E, True)
            time.sleep(1)  # 等待设备执行动作

            # 检查状态是否正常
            status = self.read_status()
            if status == 0:  # STATUS_READY
                print("计数已清除")
            else:
                print(f"计数清除后状态异常: {status}")

        finally:
            # 动作完成后，重置寄存器为 0x0000
            print("重置计数寄存器...")
            self.write_coil(0x081E, False)
